# usbWatcher.py (优化版)
import threading
import time
import win32gui

WM_DEVICECHANGE = 0x0219
DBT_DEVICEARRIVAL = 0x8000
DBT_DEVICEREMOVECOMPLETE = 0x8004


class UsbWatcher:
    _class_registered = False

    def __init__(self, callback, debounce_interval=2.0):
        self.callback = callback
        self.debounce_interval = debounce_interval
        self.last_trigger_time = 0
        self._stop_event = threading.Event()
        self._thread = None

    def start(self):
        if self._thread and self._thread.is_alive():
            return
        self._thread = threading.Thread(target=self._message_loop, daemon=True)
        self._thread.start()

    def stop(self):
        if self._thread:
            self._stop_event.set()
            # 不需要 join，因为它是后台线程

    def _message_loop(self):
        wc = win32gui.WNDCLASS()
        wc.lpfnWndProc = self._wnd_proc
        wc.lpszClassName = f"UsbWatcherWindowClass_{id(self)}"  # 使用唯一类名避免冲突

        # 注册窗口类
        try:
            win32gui.RegisterClass(wc)
        except Exception as e:
            # 如果类已注册 (例如在代码热重载后)，忽略错误
            if hasattr(e, "winerror") and e.winerror == 1410:
                pass
            else:
                print(f"无法注册窗口类: {e}")
                return

        # 创建一个不可见的消息窗口
        hwnd = win32gui.CreateWindow(wc.lpszClassName, "", 0, 0, 0, 0, 0, 0, 0, 0, None)
        if not hwnd:
            print("无法创建消息窗口。")
            return

        while not self._stop_event.is_set():
            win32gui.PumpWaitingMessages()
            time.sleep(0.1)

        win32gui.DestroyWindow(hwnd)
        win32gui.UnregisterClass(wc.lpszClassName, None)

    def _wnd_proc(self, hwnd, msg, wparam, lparam):
        if msg == WM_DEVICECHANGE:
            now = time.time()
            if now - self.last_trigger_time > self.debounce_interval:
                self.last_trigger_time = now
                if callable(self.callback):
                    action = "设备连接" if wparam == DBT_DEVICEARRIVAL else "设备断开"
                    print(f"🔌 USB 状态变化: {action}，准备刷新设备列表...")

                    # 启动一个工作线程来执行回调，避免阻塞消息循环
                    threading.Thread(target=self._delayed_callback, daemon=True).start()
        return win32gui.DefWindowProc(hwnd, msg, wparam, lparam)

    def _delayed_callback(self):
        """
        在工作线程中执行，包含延迟以等待系统稳定。
        """
        # 等待1-2秒，让操作系统完成设备枚举
        time.sleep(2)
        print(">>> 开始刷新设备列表...")
        self.callback()